package ro.flashbite.game_engine.data
{
	import ro.flashbite.game_engine.data.intefaces.IAppDataStorage;
	import ro.flashbite.game_engine.data.intefaces.IPlayerData;
	import ro.flashbite.game_engine.data.intefaces.IScoreObject;
	import ro.flashbite.interfaces.IDestroyable;

	/**
	 * Holds all important data about application and players
	 * 
	 * v 1.0
	 *  
	 * @author Adrian Barbu
	 */	
	public final class AppDataStorage implements IAppDataStorage, IDestroyable
	{
		private static const SERIALIZED_APP_VOLUME			:	String = "applicationVolume";
		private static const SERIALIZED_CURRENT_PLAYER		:	String = "currentPlayer";
		private static const SERIALIZED_ALL_PLAYERS			:	String = "allPlayers";
		
		private var _applicationVolume	:	Number;
		private var _currentPlayer		:	IPlayerData;
		private var _allPlayers			:	Vector.<PlayerData>;
		
		// ================================================================================================================================
		// CONSTRUCTOR
		// ================================================================================================================================
		
		public function AppDataStorage(appVolume:Number = 1, currentPlayer:IPlayerData = null, allPlayers:Vector.<PlayerData> = null)
		{
			_constructor(appVolume, currentPlayer, allPlayers);
		}
		private function _constructor(appVolume:Number, currentPlayer:IPlayerData, allPlayers:Vector.<PlayerData>):void
		{
			_applicationVolume = appVolume;
			_currentPlayer = currentPlayer;
			_allPlayers = allPlayers;
			
			//push the current player in _allPlayers; we will have the same character saved here when will read from sharedObject
			var samePlayerAlreadySaved:IPlayerData = getPlayer(_currentPlayer.playerName);
			if (samePlayerAlreadySaved) {
				_currentPlayer = samePlayerAlreadySaved;
			} else {
				_allPlayers.push(_currentPlayer);
			}
		}
		
		// ================================================================================================================================
		// IAppDataStorage
		// ================================================================================================================================
		
		public function get applicationVolume()			  : Number  { return _applicationVolume; }
		public function set applicationVolume(vol:Number) : void 	{ _applicationVolume = vol;  }
		
		public function get currentPlayer_Name()					: String { return (_currentPlayer) ? _currentPlayer.playerName : null; 	}
		//has the role to create/'push' new player if the name is unique and to get and set a prior created player 
		public function set currentPlayer_Name(playerName:String)	: void 	 
		{ 
			//if (_currentPlayer) _currentPlayer.playerName = playerName; 
			var samePlayerAlreadySaved:IPlayerData = getPlayer(playerName);
			if (samePlayerAlreadySaved) {
				_currentPlayer = samePlayerAlreadySaved;
			} else {
				//create a new one
				var newPlayer:IPlayerData = new PlayerData(playerName);
				_currentPlayer = newPlayer;
				_allPlayers.push(_currentPlayer);
			}
		}
		
		public function get currentPlayer_CharacterName()				 : String { return (_currentPlayer) ? _currentPlayer.characterName : null; }
		public function set currentPlayer_CharacterName(charName:String) : void   {	if (_currentPlayer) _currentPlayer.characterName = charName;   }
		
		public function get currentPlayer_Difficulty()			: uint { return (_currentPlayer) ? _currentPlayer.difficulty : 1; }		
		public function set currentPlayer_Difficulty(diff:uint)	: void { if (_currentPlayer) _currentPlayer.difficulty = diff;	 }
		
		public function get currentPlayer_Scores()								: Vector.<IScoreObject> { return (_currentPlayer) ? _currentPlayer.scores : null; 		}		
		public function set currentPlayer_Scores(scores:Vector.<IScoreObject>)	: void 					{ if (_currentPlayer) _currentPlayer.scores = scores; 	  		}
		public function currentPlayer_addScoreObject(scoreObj:IScoreObject)		: void 					{ if (_currentPlayer) _currentPlayer.addScoreObject(scoreObj);	}
		
		public function get currentPlayer_CharactersUnlocked()						: Vector.<String> { return (_currentPlayer) ? _currentPlayer.charactersUnlocked : null;	}
		public function set currentPlayer_CharactersUnlocked(chars:Vector.<String>)	: void 			  { if (_currentPlayer) _currentPlayer.charactersUnlocked = chars; 		}
		public function currentPlayer_addCharacterUnlocked(char:String)				: void 			  { if (_currentPlayer) _currentPlayer.addCharacterUnlocked(char); 		}
		
		public function get currentPlayer_Location()								: String { return (_currentPlayer) ? _currentPlayer.location : null; }
		public function set currentPlayer_Location(location:String)					: void   { if (_currentPlayer) _currentPlayer.location = location; 	 }
		
		public function get currentPlayer_LocationsUnlocked()						   : Vector.<String> { return (_currentPlayer) ? _currentPlayer.locationsUnlocked : null; }
		public function set currentPlayer_LocationsUnlocked(locations:Vector.<String>) : void 			 { if (_currentPlayer) _currentPlayer.locationsUnlocked = locations;  }
		public function currentPlayer_addLocationUnlocked(location:String)			   : void 			 { if (_currentPlayer) _currentPlayer.addLocationUnlocked(location);  }
		
		public function get currentPlayer()						: IPlayerData { return _currentPlayer; }
		public function set currentPlayer(player:IPlayerData)	: void 		  { _currentPlayer = player; }
		
		public function get allPlayers() : Vector.<PlayerData> { return _allPlayers; }
		
		// ================================================================================================================================
		// ISerializable
		// ================================================================================================================================
		
		public static function serialize(data:AppDataStorage):Object
		{
			var obj:Object = {},
				serializePlayerDataFunc:Function = PlayerData.serialize,
				allPlayers:Vector.<PlayerData> = data.allPlayers,
				player:IPlayerData,
				allPlayersSerialized:Array = [];
			
			//volume
			obj[SERIALIZED_APP_VOLUME] = data.applicationVolume;
			
			//current player
			obj[SERIALIZED_CURRENT_PLAYER] = serializePlayerDataFunc(data.currentPlayer);
			
			//all players
			for each (player in allPlayers) {
				allPlayersSerialized.push(serializePlayerDataFunc(player));
			}
			obj[SERIALIZED_ALL_PLAYERS] = allPlayersSerialized;
			
			return obj;
		}
		
		public static function unserialize(data:Object):AppDataStorage
		{
			var appData:AppDataStorage,
				volume:Number,
				currentPlayer:IPlayerData,
				serializedPlayer:Object,
				allSerializedPlayers:Array,
				allPlayers:Vector.<PlayerData>,
				unserializePlayerDataFunc:Function = PlayerData.unserialize;
			
			//volume
			volume = (data[SERIALIZED_APP_VOLUME] == null) ? 1 : data[SERIALIZED_APP_VOLUME];
			
			//current player
			currentPlayer = (data[SERIALIZED_CURRENT_PLAYER] == null) ? null : unserializePlayerDataFunc(data[SERIALIZED_CURRENT_PLAYER]);
			
			//all players
			allPlayers = new Vector.<PlayerData>();
			allSerializedPlayers = (data[SERIALIZED_ALL_PLAYERS] == null) ? [] : data[SERIALIZED_ALL_PLAYERS];
			for each (serializedPlayer in allSerializedPlayers) { //in sharedObjects vectors are stored with Object values
				allPlayers.push(unserializePlayerDataFunc(serializedPlayer));
			}
			
			//set data
			appData = new AppDataStorage(volume, currentPlayer, allPlayers);
			
			return appData;
		}
		
		// ================================================================================================================================
		// PRIVATE
		// ================================================================================================================================
		
		private function getPlayer(playerProp:*):IPlayerData
		{
			var player:IPlayerData,
				playerIndex:int;
			
			//check by index of element
			if (playerProp is IPlayerData) {
				playerIndex = _allPlayers.indexOf(playerProp);
				if (playerIndex > -1) return _allPlayers[playerIndex];
				//set to search for name
				playerProp = (playerProp as IPlayerData).playerName;
			} 
			
			//check by player name
			if (playerProp is String){
				for each (player in _allPlayers) {
					if (player.playerName == playerProp) {
						return player;
						break;
					}
				}
			}
			
			return null;
		}
		
		// ================================================================================================================================
		// DESTRUCTOR
		// ================================================================================================================================
		
		public function destroy():void
		{
			_currentPlayer = null;
			if (_allPlayers) {
				for each (var player:PlayerData in _allPlayers) {
					player.destroy();
				}
				_allPlayers = null;
			}
		}
	}
}